package org.dwpd.controller.system;

import cn.hutool.core.bean.BeanUtil;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.dwpd.config.OnlineUserManger;
import org.dwpd.domain.inbox.UserMessageRequest;
import org.dwpd.domain.inbox.UserMessageResponse;
import org.dwpd.domain.user.UserInfo;
import org.dwpd.service.message.MessageService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;
import java.io.IOException;
import java.util.*;

import static org.dwpd.utils.RedisConstants.LOGIN_USER_KEY;

@Slf4j
@RestController
public class WebSocketController extends TextWebSocketHandler {

    @Autowired
    private OnlineUserManger onlineUserManger;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Autowired
    private MessageService messageService;

    private ObjectMapper objectMapper = new ObjectMapper();

    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {

        try {

            String token = (String) session.getAttributes().get("token");
            if (token == null) {
                log.info("用户未登录，token为空，无法建立连接");
                return;
            }
//        Integer userId = jwtHelper.getUserId(token);
        // 进行判断 -> 用户信息链接 || 用户帖链接
        Integer messageId = (Integer) session.getAttributes().get("messageId");
        String userIdStr = (String) stringRedisTemplate.opsForHash().get(LOGIN_USER_KEY + token, "userId");
        if (userIdStr == null) {
            log.info("用户token {} 不存在", token);
            return;
        }
        Integer userId = Integer.valueOf(userIdStr);
        if (messageId == null || messageId == 0) {
            onlineUserManger.online(userId, 0, session, true);
        }
        else {
            onlineUserManger.online(userId, messageId, session, false);
        }
        log.info("[WebSocketController] 连接成功!");
//        onlineUserManger.online(10, session);
//        onlineUserManger.online(8, session);
//        onlineUserManger.online(10, session);
        } catch (Exception e) {
            log.error("WebSocket 连接处理异常", e);
        }
    }

    @Override
    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {

        // 1. 心跳检测，判断是否为 PING 消息
        if ("PING".equals(message.getPayload())) {
            // 回复 PONG，保持心跳
            session.sendMessage(new TextMessage("PONG"));
//            log.info("发送 PONG 给客户端");
            return;
        }

        log.info("[WebSocketController] 收到消息! " + message.toString());
        // 1. 先获取到当前的用户信息，用于后续进行消息转发
//        String token = (String) session.getAttributes().get("token");
//        if (token == null) {
//            log.info("[WebSocketController] user = null! 未登录用户，无法进行消息转发");
//            return;
//        }
//        Integer userId = jwtHelper.getUserId(token);
        // 2. 针对请求进行解析，把 json 格式的字符串转成一个 Java中的对象
        UserMessageRequest req = objectMapper.readValue(message.getPayload(), UserMessageRequest.class);
        String token = req.getToken();
        if (token == null) {
            log.info("[WebSocketController] user = null! 未登录用户，无法进行消息转发");
            return;
        }
        // 从缓存中获取当前登录用户的信息
        // -- 获取信息根据转发对象实时调整的，若转发对象是帖主则是获取到的用户信息是帖主的信息，若是转发对象是申请用户则获取到的是申请用户的信息
        Map<Object, Object> userMap = stringRedisTemplate.opsForHash().entries(LOGIN_USER_KEY + token);
        UserInfo userInfo = BeanUtil.fillBeanWithMap(userMap, new UserInfo(), false);

        if (req.getType() != null) {
            transferMessage(userInfo, req);
        } else {
            log.info("[WebSocketController] req.type 有误! " + message.getPayload());
        }
    }

    // 消息请求转发方法
    private void transferMessage(UserInfo fromUser, UserMessageRequest req) throws IOException {

        // 1. 先构建一个待转发的对象 --> UserMessageResponse
        UserMessageResponse resp = getUserMessageResponse(fromUser, req);
        List<Integer> userIds = null;
        // 2. 获取帖主对应的WebSocketSession，进而发送消息
        // 2.1 先将请求信息添加至数据库，若帖主未在线,后续帖主用户登录后自动获取历史记录
        if (req.getType().equals("requestMessage")) {
            resp.setContent("<用户>" + fromUser.getUserName() + "申请上座!");
            messageService.addRequestMessage(resp);
        }
        else if (req.getType().equals("agreeMessage")) {
            resp.setContent("<帖主>" + fromUser.getUserName() + "同意了你的上座请求!");
            // 若为同意请求，将请求信息添加至数据库中，over_flag = 1, agree_flag = 1, reject_flag = 0
            messageService.addAgreeMessage(resp);
        }
        else if (req.getType().equals("rejectMessage")) {
            resp.setContent("<帖主>" + fromUser.getUserName() + "拒绝了你的上座请求!");
            // 若为拒绝请求，将请求信息添加至数据库中，over_flag = 1, reject_flag = 1, agree_flag = 0
            messageService.addInformMessage(resp);
        }
        else if (req.getType().equals("lockMessage")) {

            // 上座用户信息
//            userIds = Arrays.stream(req.getIds().split(",")).map(Integer::valueOf).toList();
            String ids = req.getIds();
            if (ids == null || ids.trim().isEmpty()) {
                // 如果 ids 为空，返回一个空列表或者处理错误情况
                userIds = Collections.emptyList();
            } else {
                userIds = Arrays.stream(ids.split(","))
                        .filter(id -> !id.trim().isEmpty()) // 确保过滤掉空字符串
                        .map(Integer::valueOf)
                        .toList();
            }
            // 锁帖通知
            // 2.1.1 通知其它正在详情页的用户 帖主已锁帖信息
            List<WebSocketSession> sessions = onlineUserManger.getSessionByMessageId(resp.getMessageId());
            resp.setType("InformLockMessage");
            resp.setAcceptUserId(0); //表示群发
            resp.setContent("当前任务已上锁，非上座用户无法进入");
            for (WebSocketSession session : sessions) {
                if (session != null) {
                    try {
                        if (session.isOpen()) {
                            session.sendMessage(new TextMessage(objectMapper.writeValueAsString(resp)));
                        }
                    } catch (IllegalStateException  e) {
                        log.info("session已关闭，无法发送消息给它");
                    }
                }
            }
            // 2.1.2 发送完通知后，用户帖中的session集体下线，上座用户需重新进入详情页建立连接
            onlineUserManger.offLineMessage(resp.getMessageId());

            // 2.1.3 上座用户收件箱通知
            resp.setType("lockMessage");
            resp.setContent("<帖主>" + fromUser.getUserName() + "：任务已上锁，可前往任务中心查看任务详情");
            for (Integer userId : userIds) {
                resp.setAcceptUserId(userId);
                messageService.addInformMessage(resp);
            }
        }
        else if (req.getType().equals("commentMessage")) {
            // 用户评论
            List<WebSocketSession> sessions = onlineUserManger.getSessionByMessageId(resp.getMessageId());
            if (sessions == null || sessions.isEmpty()) {
                log.info("当前详情页无用户在线，数据已存入数据库");
                return;
            }
            resp.setContent("<拼车任务>" + resp.getMessageId() +  "添加新的评论");
            resp.setAcceptUserId(0);
//            log.info("<sessions> : {}", sessions);
            for (WebSocketSession session : sessions) {
                if (session != null) {
                    try {
                        if (session.isOpen()) {
                            session.sendMessage(new TextMessage(objectMapper.writeValueAsString(resp)));
                        }
                    } catch (IllegalStateException  e) {
                        log.info("session已关闭，无法发送消息给它");
                    }
                }
            }

            return; // 不需要进入下述转发操作
        }
        else if (req.getType().equals("accomplishMessage")) {
            // 帖子任务完成通知
            if (req.getIds() != null && !req.getIds().isEmpty()) {
                userIds = Arrays.stream(req.getIds().split(","))
                        .filter(id -> id != null && !id.trim().isEmpty())
                        .map(Integer::valueOf).toList();
                resp.setContent("<帖主>" + fromUser.getUserName() + "：本次车程已完成，欢迎下次同行！！");
                for (Integer userId : userIds) {
                    resp.setAcceptUserId(userId);
                    messageService.addInformMessage(resp);
                }
            }
        }

        // 把 resp 这个 Java对象 转成 json格式字符串
        String respJson = objectMapper.writeValueAsString(resp);
        log.info("[transferMessage] respJson: {}", respJson);
        // 2.2 获取接收用户对应的WebSocketSession
        if (userIds != null) {
//            log.info("userIds不为空: {}", userIds);
            List<WebSocketSession> sessions = userIds.stream().map(userId -> onlineUserManger.getSession(userId)).toList();
//            log.info("sessions：======{}", sessions);
            for (WebSocketSession webSocketSession : sessions) {
                if (webSocketSession != null) {
                    try {
                        if (webSocketSession.isOpen()) {
                            webSocketSession.sendMessage(new TextMessage(respJson));
                        }
                    } catch (IllegalStateException  e) {
                        log.info("session已关闭，无法发送消息给它");
                    }
                }
            }
        }
        else {
            WebSocketSession webSocketSession = onlineUserManger.getSession(req.getAcceptUserId());
            if (webSocketSession != null) {

                // 若接收用户在线，即刻发送请求;
                try {
                    if (webSocketSession.isOpen()) {
                        webSocketSession.sendMessage(new TextMessage(respJson));
//                        log.info("发给单个用户:{}",webSocketSession);
                    }
                } catch (IllegalStateException  e) {
                    log.info("session已关闭，无法发送消息给它");
                }   
            }
            else {
                // 如果为空，表示该用户未登录
                log.info("用户未在线，请求信息已保存，等待用户回复: {}", respJson);
            }
        }
    }

    @Override
    public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
        log.info("[WebSocketController] 连接异常! " + exception.toString());
        String token = (String) session.getAttributes().get("token");
        String userIdStr = (String) stringRedisTemplate.opsForHash().get(LOGIN_USER_KEY + token, "userId");
        if (userIdStr == null) {
            return;
        }
        Integer userId = Integer.valueOf(userIdStr);
        String key = LOGIN_USER_KEY + token;
        onlineUserManger.offline(userId, session, key);
    }

    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
        log.info("[WebSocketController] 连接关闭 " + status.toString());
        String token = (String) session.getAttributes().get("token");
        String userIdStr = (String) stringRedisTemplate.opsForHash().get(LOGIN_USER_KEY + token, "userId");
        if (userIdStr == null) {
            return;
        }
        Integer userId = Integer.valueOf(userIdStr);
        String key = LOGIN_USER_KEY + token;
        onlineUserManger.offline(userId, session, key);
    }

    private static UserMessageResponse getUserMessageResponse(UserInfo fromUser, UserMessageRequest req) {
        UserMessageResponse resp = new UserMessageResponse();
        resp.setType(req.getType());
        resp.setMessageId(req.getMessageId());
        resp.setAcceptUserId(req.getAcceptUserId());
        resp.setFromUserId(fromUser.getUserId());
        resp.setFromUserName(fromUser.getUserName());
        resp.setFromUserImage(fromUser.getUserImage());
        return resp;
    }
}
